<template>
  <div class="cg-checklist" ref="checklistRef">
    <div class="cg-checklist-body">
      <cg-scrollbar ref="scrollbarRef" tag="div">
        <div class="cg-checklist-panel">
          <div
            :class="['cg-checklist-item', { active: active === `${item.id}` }]"
            v-for="item in list"
            @dblclick="openRow(item)"
            @click="active = `${item.id}`"
            :key="`${item.id}`"
          >
            {{ item.name }}
          </div>
        </div>
      </cg-scrollbar>
    </div>
    <div class="cg-checklist-footer">
      <cg-button size="small" @click="moveRow('up')">上移</cg-button>
      <cg-button size="small" @click="moveRow('dn')">下移</cg-button>
      <cg-button size="small" @click="openRow()">
        <span v-show="active">编辑</span>
        <span v-show="!active">添加</span>
      </cg-button>
      <cg-button size="small" @click="deleteRow">删除</cg-button>
    </div>

    <cg-dialog class="cg-checklist-dialog" v-model:visible="visible" title="选择列表">
      <div class="cg-checklist-dialog-content">
        <div class="left-col">
          <cg-image :path="dialogSelectedItem.head_path"></cg-image>
        </div>
        <div class="right-col">
          <cg-select v-model="dialogSelected" :options="options"></cg-select>
          <div class="cg-checklist-description">
            <div>{{ dialogSelectedItem.description }}</div>
          </div>
        </div>
      </div>
      <template v-slot:footer>
        <cg-button @click="dialogConfirm">确定</cg-button>
      </template>
    </cg-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { limitValue, switchValue, isInitString, isFormalEqual } from '../../tools'
import _ from 'lodash'

// 定义组件名称
defineOptions({
  name: 'cg-checklist'
})

// 定义props
const props = defineProps<{
  modelValue: any[]
  disabled: boolean
  options: Array<{
    id: number | string
    name: string
    description?: string
    head_path?: string
    [key: string]: any
  }>
}>()

// 定义emits
const emit = defineEmits(['update:modelValue'])

// 响应式变量
const visible = ref(false)
const selected = ref<any[]>([])
const active = ref<string | undefined>(undefined)
const dialogSelected = ref<number | string | undefined>(undefined)
const checklistRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<HTMLElement | null>(null)

// 点击外部处理
function handleClickOutside(event: MouseEvent) {
  if (checklistRef.value && !checklistRef.value.contains(event.target as Node)) {
    setTimeout(() => {
      active.value = undefined
    }, 0)
  }
}

// 生命周期钩子
onMounted(() => {
  updateValue()
  document.addEventListener('click', handleClickOutside)
})

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside)
})

// 计算属性
const list = computed(() => {
  if (Array.isArray(props.options)) {
    return _.compact(
      selected.value.map((id) => props.options?.find((item) => isFormalEqual(item.id, id)))
    )
  }
  return []
})

const dialogSelectedItem = computed(() => {
  return switchValue(dialogSelected.value, props.options, 'id', _.toString)
})

// 监听modelValue变化
watch(
  () => props.modelValue,
  () => {
    updateValue()
  },
  { immediate: true }
)

// 生命周期钩子
onMounted(() => {
  updateValue()
})

// 方法
function updateValue() {
  selected.value = Array.isArray(props.modelValue) ? props.modelValue : []
}

function moveRow(type: 'up' | 'dn') {
  if (Array.isArray(selected.value)) {
    let list = [...selected.value]
    let currentIndex = list.findIndex((value) => isFormalEqual(value, active.value))
    if (currentIndex === -1) {
      return
    }
    let index = currentIndex
    let max = list.length - 1
    let min = 0
    if (type === 'up') {
      index = limitValue(index - 1, min, max)
    }

    if (type === 'dn') {
      index = limitValue(index + 1, min, max)
    }
    if (index === currentIndex) {
      return
    }
    let save = list[index]
    list[index] = list[currentIndex]
    list[currentIndex] = save
    selected.value = list
    emit('update:modelValue', selected.value)
  }
}

function openRow(item?: { id: number | string }) {
  if (item) {
    dialogSelected.value = _.toNumber(item.id)
  } else {
    dialogSelected.value = active.value
  }
  visible.value = true
}

function deleteRow() {
  if (isInitString(active.value)) {
    let save = Array.isArray(selected.value) ? selected.value : []
    _.remove(save, (v) => isFormalEqual(v, active.value))
    selected.value = save
    active.value = undefined
    emit('update:modelValue', selected.value)
  }
}

function dialogConfirm() {
  let save = Array.isArray(selected.value) ? selected.value : []
  if (dialogSelectedItem.value && dialogSelectedItem.value.id) {
    save.push(dialogSelectedItem.value.id)
    save = _.uniq(save)
    selected.value = save
    visible.value = false
    dialogSelected.value = undefined
    emit('update:modelValue', selected.value)
  }
}

// 暴露方法
defineExpose({
  updateValue
})
</script>

<style lang="scss">
@use './style.scss';
</style>
